package com.ruoyi.app.business.project;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.json.JSONUtil;
import com.ruoyi.app.business.account.CompanyAccountBusiness;
import com.ruoyi.app.business.dict.DictBusiness;
import com.ruoyi.app.business.file.FileBusiness;
import com.ruoyi.app.business.message.MessageBusiness;
import com.ruoyi.app.business.regiion.RegionBusiness;
import com.ruoyi.app.config.platform.PlatFormConfig;
import com.ruoyi.app.config.util.UserUtil;
import com.ruoyi.app.converter.FileConverter;
import com.ruoyi.app.converter.ProjectConverter;
import com.ruoyi.app.domain.common.DefaultUploadResult;
import com.ruoyi.app.domain.common.UploadResult;
import com.ruoyi.app.domain.project.Demand;
import com.ruoyi.app.domain.project.ProjectDetail;
import com.ruoyi.app.domain.project.ProjectObj;
import com.ruoyi.app.domain.project.ProjectSimple;
import com.ruoyi.app.domain.project.ReserveFundDetail;
import com.ruoyi.app.domain.project.Team;
import com.ruoyi.app.domain.project.change.ProjectChangeRecord;
import com.ruoyi.app.domain.project.delivery.ProjectDelivery;
import com.ruoyi.app.domain.project.upload.TeamUploadResult;
import com.ruoyi.common.core.domain.R;
import com.ruoyi.common.core.enums.YesNoEnum;
import com.ruoyi.common.core.exception.ServiceException;
import com.ruoyi.common.core.utils.CommonUtils;
import com.ruoyi.common.core.utils.LocalDateUtils;
import com.ruoyi.common.core.utils.PageUtils;
import com.ruoyi.common.core.utils.StringUtils;
import com.ruoyi.common.core.utils.file.FileTypeUtils;
import com.ruoyi.common.core.utils.file.MimeTypeUtils;
import com.ruoyi.common.core.utils.poi.ExcelUtil;
import com.ruoyi.common.core.web.page.CommonPageInfo;
import com.ruoyi.common.redis.service.GlobalKeyService;
import com.ruoyi.common.redis.service.RedisService;
import com.ruoyi.service.company.entity.CompanyEntity;
import com.ruoyi.service.company.service.CompanyService;
import com.ruoyi.service.dict.enums.DictTypeEnum;
import com.ruoyi.service.file.entity.FileContentEntity;
import com.ruoyi.service.message.enums.MessageTemplateEnum;
import com.ruoyi.service.project.entity.ProjectEntity;
import com.ruoyi.service.project.entity.ProjectExtEntity;
import com.ruoyi.service.project.entity.ProjectLogEntity;
import com.ruoyi.service.project.enums.ProjectLogTypeEnum;
import com.ruoyi.service.project.enums.ProjectStatusEnum;
import com.ruoyi.service.project.model.PostInfo;
import com.ruoyi.service.project.model.ProjectLogDetail;
import com.ruoyi.service.project.model.ProjectLogModel;
import com.ruoyi.service.project.query.ProjectLogBaseQuery;
import com.ruoyi.service.project.query.ProjectQueryForDemander;
import com.ruoyi.service.project.query.ProjectQueryForLabor;
import com.ruoyi.service.project.query.ProjectQueryForPlatform;
import com.ruoyi.service.project.service.LaborFavouriteService;
import com.ruoyi.service.project.service.ProjectExtService;
import com.ruoyi.service.project.service.ProjectLaborService;
import com.ruoyi.service.project.service.ProjectLogService;
import com.ruoyi.service.project.service.ProjectService;
import com.ruoyi.service.project.service.ProjectSuddenService;
import com.ruoyi.service.region.entity.RegionEntity;
import com.ruoyi.service.user.entity.UserEntity;
import com.ruoyi.service.user.enums.UserTypeEnum;
import com.ruoyi.service.user.model.UserInfoModel;
import com.ruoyi.service.user.service.UserService;
import com.ruoyi.system.api.RemoteFileService;
import com.ruoyi.system.api.domain.SysFile;
import java.io.IOException;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.concurrent.TimeUnit;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import javax.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.support.TransactionTemplate;
import org.springframework.web.multipart.MultipartFile;

/**
 * <p>
 * 作用：项目相关业务
 * </p>
 *
 * @author Zane
 * @since 2025-10-10 2:19
 */
@Slf4j
@Component
public class ProjectBusiness {

  @Resource
  private ProjectService projectService;
  @Resource
  private ProjectExtService projectExtService;
  @Resource
  private ProjectLogService projectLogService;
  @Resource
  private ProjectLaborBusiness projectLaborBusiness;
  @Resource
  private ProjectDeliveryBusiness projectDeliveryBusiness;
  @Resource
  private CompanyService companyService;
  @Resource
  private CompanyAccountBusiness companyAccountBusiness;
  @Resource
  private GlobalKeyService globalKeyService;
  @Resource
  private FileBusiness fileBusiness;
  @Resource
  private PlatFormConfig platFormConfig;

  @Resource
  private RemoteFileService remoteFileService;

  @Resource
  private TransactionTemplate transactionTemplate;

  @Resource
  private UserService userService;
  @Resource
  private DictBusiness dictBusiness;
  @Resource
  private RegionBusiness regionBusiness;
  @Resource
  private MessageBusiness messageBusiness;
  @Resource
  private ProjectSettleBusiness projectSettleBusiness;
  @Resource
  private RedisService redisService;
  @Resource
  private ProjectSuddenBusiness projectSuddenBusiness;
  @Resource
  private LaborFavouriteService labourFavouriteService;
  @Autowired
  private ProjectSuddenService projectSuddenService;
  @Autowired
  private ProjectLaborService projectLaborService;


  /**
   * 获取项目列表
   */
  public CommonPageInfo<ProjectSimple> listForDemander(ProjectQueryForDemander query) {
    //项目方项目列表,我所在公司的项目列表
    final Long companyId = UserUtil.getLoginUser().getCompanyId();
    CommonPageInfo<ProjectEntity> pageInfo = PageUtils.startPage(query.getPageNum(),
        query.getPageSize());
    pageInfo.initData(Optional.ofNullable(projectService.listForDemander(query, companyId))
        .orElseGet(ArrayList::new));
    return convert(pageInfo);
  }


  /**
   * 获取项目列表
   */
  public CommonPageInfo<ProjectSimple> listForLabor(ProjectQueryForLabor query) {
    //劳务方项目列表,取招募中的项目
    CommonPageInfo<ProjectEntity> pageInfo = PageUtils.startPage(query.getPageNum(),
        query.getPageSize());
    pageInfo.initData(Optional.ofNullable(projectService.listForLabor(query))
        .orElseGet(ArrayList::new));
    return convert(pageInfo);

  }

  /**
   * 获取项目列表
   */
  public CommonPageInfo<ProjectSimple> listForPlatform(ProjectQueryForPlatform query) {
    //劳务方项目列表,取招募中的项目
    CommonPageInfo<ProjectEntity> pageInfo = PageUtils.startPage(query.getPageNum(),
        query.getPageSize());
    pageInfo.initData(Optional.ofNullable(projectService.listForPlatform(query))
        .orElseGet(ArrayList::new));
    return convert(pageInfo);
  }

  public ProjectDetail detail(String projectId) {
    //项目信息
    final ProjectEntity projectEntity = CommonUtils.requireNotNull(
        projectService.getById(projectId),
        "项目ID不合法");
    final ProjectDetail projectDetail = ProjectConverter.INSTANCE.toProjectDetail(projectEntity);
    //项目扩展信息
    final ProjectExtEntity projectExtEntity = projectExtService.selectByProjectId(projectId);
    projectDetail.setReserveFundDetailFile(projectExtEntity.getReserveFundDetailFile())
        .setReserveFundDetailFileKey(projectExtEntity.getReserveFundDetailFileKey())
        .setTeamListFile(projectExtEntity.getTeamListFile())
        .setTeamListFileKey(projectExtEntity.getTeamListFileKey())
        .setDemandListFile(projectExtEntity.getDemandListFile())
        .setDemandListFileKey(projectExtEntity.getDemandListFileKey())
    ;
    //补充用户信息
    final List<Long> userIds = Stream.of(projectEntity.getCreateBy(),
        projectEntity.getProjectLeader()).collect(Collectors.toList());
    final Map<Long, UserEntity> userEntityMap = userService.userMapByIds(userIds);
    projectDetail.setProjectLeaderName(
            userEntityMap.get(projectEntity.getProjectLeader()).getName())
        .setCreateByName(userEntityMap.get(projectEntity.getCreateBy()).getName());
    //补充公司信息
    final CompanyEntity companyInfo = CommonUtils.requireNotNull(
        companyService.getById(projectEntity.getComId()), "数据有误,请联系管理员");
    projectDetail.setComName(companyInfo.getComName());
    //补充文件信息
    List<String> fileKeys = Arrays.asList(projectExtEntity.getReserveFundDetailFileKey(),
        projectExtEntity.getTeamListFileKey(), projectExtEntity.getDemandListFileKey());
    final Map<String, FileContentEntity> fileMap = fileBusiness.mapByFileKeys(
        fileKeys);
    if (StringUtils.isNotBlank(projectExtEntity.getReserveFundDetailFileKey())) {
      projectDetail.setReserveFundDetailFileInfo(FileConverter.INSTANCE.entity2Info(
          fileMap.get(projectExtEntity.getReserveFundDetailFileKey())));
    }
    if (StringUtils.isNotBlank(projectExtEntity.getTeamListFileKey())) {
      projectDetail.setTeamListFileInfo(
          FileConverter.INSTANCE.entity2Info(fileMap.get(projectExtEntity.getTeamListFileKey())));
    }
    if (StringUtils.isNotBlank(projectExtEntity.getDemandListFileKey())) {
      projectDetail.setDemandListFileInfo(
          FileConverter.INSTANCE.entity2Info(fileMap.get(projectExtEntity.getDemandListFileKey())));
    }
    //是否收藏
    if (Objects.nonNull(UserUtil.getLoginUser())
        && UserTypeEnum.LABOR_USER.eq(UserUtil.getLoginUser().getUserType())) {
      //是否收藏
      boolean isCollect = labourFavouriteService.checkIsCollect(UserUtil.getUserId(), projectId);
      projectDetail.setCollectFlag(YesNoEnum.getByValue(isCollect).getCode());
    }
    return projectDetail;
  }

  /**
   * 创建项目
   *
   * @param projectObj 项目对象
   */
  public void create(ProjectObj projectObj) {
    checkProjectObj(projectObj);
    //转换为实体对象
    final ProjectEntity projectEntity = ProjectConverter.INSTANCE.toProjectEntity(projectObj);
    final ProjectExtEntity projectExtEntity = ProjectConverter.INSTANCE.toProjectExtEntity(
        projectObj);
    //填充基础信息
    fillBaseInfo(projectEntity, projectExtEntity);
    //补充岗位招聘信息
    calcPostInfo(projectEntity, projectExtEntity.getTeamListFileKey());
    //1 旧值空->新值
    transactionTemplate.executeWithoutResult(transactionStatus -> {
      final String projectId = globalKeyService.globalKey("PN");
      projectEntity.setId(projectId);
      projectExtEntity.setProjectId(projectId);
      //保存主表数据
      projectService.save(projectEntity);
      //报存扩展表数据
      projectExtService.save(projectExtEntity);
      //走发布流程
      if (YesNoEnum.YES.eqCode(projectObj.getPublishFlag())) {
        publish(projectEntity.getId());
      }
    });
  }

  /**
   * 变更项目
   *
   * @param projectObj 项目对象
   */
  public void modify(ProjectObj projectObj) {
    checkProjectObj(projectObj);
    if (Objects.isNull(projectObj.getId())) {
      throw new ServiceException("项目ID不能为空");
    }
    //判断数据权限
    //1 取旧值,数据值对比,记录差异信息
    final ProjectEntity projectEntity = CommonUtils.requireNotNull(
        projectService.getById(projectObj.getId()), "项目ID不合法");
    //判断项目是否是可编辑状态
    if (!ProjectStatusEnum.couldEdit(projectEntity.getStatus())) {
      throw new ServiceException("当前项目不满足编辑条件");
    }
    //判断用户数据权限
    final UserInfoModel loginUser = UserUtil.getLoginUser();
    //项目方,同一公司
    if (UserTypeEnum.DEMANDER_USER.eq(loginUser.getUserType())) {
      //判断公司权限
      CommonUtils.assertsTrueWithMessage(projectEntity.getComId().equals(loginUser.getCompanyId()),
          "用户无该项目操作权限");
    }
    //项目leader
    if (UserTypeEnum.LABOR_USER.eq(loginUser.getUserType())) {
      CommonUtils.assertsTrueWithMessage(
          projectEntity.getProjectLeader().equals(loginUser.getUserId())
          , "用户无该项目操作权限");
    }
    final ProjectExtEntity projectExtEntity = projectExtService.selectByProjectId(
        projectObj.getId());
    //构建旧值
    final ProjectObj oldValue = copyToObject(projectEntity, projectExtEntity);
    if (YesNoEnum.YES.eqCode(oldValue.getHasReserveFund())
        && YesNoEnum.NO.eqCode(projectObj.getHasReserveFund())) {
      throw new ServiceException("备用金不能由[是]转为[否]");
    }
    final ProjectLogModel projectLogModel = buildAndCheckProjectChangeLog(oldValue, projectObj);
    //记录旧的锁定金额
    final BigDecimal oldLockedAmount = projectEntity.getLockedAmount();
    //塞入值
    updateEntity(projectEntity, projectExtEntity, projectObj);
    //填充基础信息
    fillBaseInfo(projectEntity, projectExtEntity);
    //补充岗位招聘信息
    calcPostInfo(projectEntity, projectExtEntity.getTeamListFileKey());
    transactionTemplate.executeWithoutResult(transactionStatus -> {
      projectService.updateById(projectEntity);
      projectExtService.updateById(projectExtEntity);
      if (ProjectStatusEnum.hasPublished(projectEntity.getStatus())) {
        //记录变化日志
        projectLogService.saveLog(projectLogModel, UserUtil.getLoginUser());
        //判断是否有锁定金额变化
        if (projectEntity.getLockedAmount().compareTo(oldLockedAmount) != 0) {
          companyAccountBusiness.lockAmount(
              projectEntity.getLockedAmount().subtract(oldLockedAmount), projectEntity.getComId(),
              projectEntity.getId());
        }
      }
      //新建项目未发布,并且需要发布
      if (YesNoEnum.YES.eqCode(projectObj.getPublishFlag())
          && ProjectStatusEnum.CREATE.eqCode(projectEntity.getStatus())) {
        publish(projectEntity.getId());
      }

    });
  }

  public CommonPageInfo<ProjectChangeRecord> changeRecord(ProjectLogBaseQuery query) {
    //劳务方项目列表,取招募中的项目
    CommonPageInfo<ProjectLogEntity> pageInfo = PageUtils.startPage(query.getPageNum(),
        query.getPageSize());
    pageInfo.initData(Optional.ofNullable(projectLogService.listByProjectId(query.getProjectId()))
        .orElseGet(ArrayList::new));
    return pageInfo.convert(this::projectChangeConvert);
  }

  private ProjectChangeRecord projectChangeConvert(ProjectLogEntity entity) {
    final ProjectChangeRecord changeRecord = ProjectConverter.INSTANCE.toProjectChangeRecord(
        entity);
    final ProjectLogDetail detailInfo = JSONUtil.toBean(entity.getChangeData(),
        ProjectLogDetail.class);
    changeRecord.setChangeType(detailInfo.getChangeType())
        .setChangeField(detailInfo.getChangeField())
        .setBefore(detailInfo.getBefore())
        .setAfter(detailInfo.getAfter())
        .setIsFileUrl(detailInfo.getIsFileUrl());
    return changeRecord;
  }

  private ProjectObj copyToObject(ProjectEntity projectEntity, ProjectExtEntity projectExtEntity) {
    return ProjectConverter.INSTANCE.toProjectObj(projectEntity)
        .setReserveFundDetailFile(projectExtEntity.getReserveFundDetailFile())
        .setReserveFundDetailFileKey(projectExtEntity.getReserveFundDetailFileKey())
        .setTeamListFile(projectExtEntity.getTeamListFile())
        .setTeamListFileKey(projectExtEntity.getTeamListFileKey())
        .setDemandListFile(projectExtEntity.getDemandListFile())
        .setDemandListFileKey(projectExtEntity.getDemandListFileKey());
  }

  /**
   * 发布项目
   *
   * @param projectId 项目ID
   */
  @Transactional(rollbackFor = Exception.class)
  public void publish(String projectId) {
    //项目方发布
    final ProjectEntity project = CommonUtils.requireNotNull(
        projectService.getById(projectId), "项目ID不合法");
    //检查状态
    CommonUtils.assertsTrueWithMessage(
        ProjectStatusEnum.CREATE.eqCode(project.getStatus()), "状态不满足发布条件");
    //检查用户权限
    final Long companyId = UserUtil.getLoginUser().getCompanyId();
    if (!companyId.equals(project.getComId())) {
      //不具有发布权限
      throw new ServiceException("用户无该项目操作权限");
    }
    // 锁定项目金额
    final BigDecimal lockedAmount = platFormConfig.calculateAmountContainCommission(
        project.getProjectBudget());
    companyAccountBusiness.lockAmount(lockedAmount, companyId, projectId);
    //
    project.setStatus(ProjectStatusEnum.PUBLISH.getCode())
        .setLockedAmount(lockedAmount)
        .setUpdateBy(UserUtil.getUserId())
        .setUpdateTime(LocalDateTime.now());
    projectService.updateById(project);
    //记录日志
    projectLogService.saveLog(
        buildProjectLogSimple(projectId, ProjectLogTypeEnum.PROJECT_PUBLISH, null,
            StringUtils.format("项目ID:{}", project.getId())),
        UserUtil.getLoginUser());
    //发送消息
    messageBusiness.addMessage(MessageTemplateEnum.A1, buildProperties(project), project.getId(),
        project.getProjectLeader(), companyService.getNameById(companyId), project.getCreateBy());
  }

  /**
   * 交付项目
   */
  public void delivery(ProjectDelivery deliveryInfo) {
    projectDeliveryBusiness.delivery(deliveryInfo);
  }

  /**
   * 上传团队列表
   *
   * @param file 文件
   * @return 上传结果
   */
  public TeamUploadResult uploadTeamList(MultipartFile file) {
    final DefaultUploadResult<Team> uploadResult = buildTeamUploadResult(file, Team.class,
        this::dealTeamList);
    TeamUploadResult teamUploadResult = new TeamUploadResult();
    teamUploadResult.setFileUrl(uploadResult.getFileUrl());
    teamUploadResult.setFileKey(uploadResult.getFileKey());
    teamUploadResult.setFileName(uploadResult.getFileName());
    teamUploadResult.setLaborCost(uploadResult.getList().stream()
        .map(Team::getSalaryTotal)
        .reduce(BigDecimal::add)
        .orElse(BigDecimal.ZERO));
    return teamUploadResult;
  }

  /**
   * 上传备用金明细
   *
   * @param file 文件
   * @return 上传结果
   */
  public UploadResult uploadReserveFundDetailList(MultipartFile file) {
    return transUploadResult(
        buildTeamUploadResult(file, ReserveFundDetail.class, this::dealReserveFundDetail));
  }

  /**
   * 上传需求列表
   *
   * @param file 文件
   * @return 上传结果
   */
  public UploadResult uploadDemandList(MultipartFile file) {
    return transUploadResult(buildTeamUploadResult(file, Demand.class, this::dealDemandList));
  }

  private UploadResult transUploadResult(DefaultUploadResult<?> uploadResult) {
    return new UploadResult()
        .setFileName(uploadResult.getFileName())
        .setFileUrl(uploadResult.getFileUrl())
        .setFileKey(uploadResult.getFileKey());
  }

  /**
   * 转化为执行中
   */
  public void toExecution() {
    //查询所有开始时间已经开始,并且状态为发布的数据,状态变成执行中
    final List<ProjectEntity> projectEntityList = projectService.publishAndNeedStart();
    if (CollUtil.isEmpty(projectEntityList)) {
      return;
    }
    projectEntityList.forEach(projectEntity -> {
      projectEntity.setStatus(ProjectStatusEnum.ON_EXECUTION.getCode());
    });
    transactionTemplate.executeWithoutResult(status -> {
      projectService.updateBatchById(projectEntityList);
      projectEntityList.forEach(project -> {
        //获得雇佣信息
        final List<Long> userIds = projectLaborBusiness.listHiredUserByProjectId(
            project.getId());
        if (CollUtil.isEmpty(userIds)) {
          return;
        }
        messageBusiness.addMessage(MessageTemplateEnum.A2,
            buildProperties(project), project.getId(),
            userIds, companyService.getNameById(project.getComId()), project.getProjectLeader());
      });
    });
  }

  private Map<String, String> buildProperties(ProjectEntity project) {
    return new HashMap<String, String>() {{
      put("projectName", project.getProjectName());
      put("projectEndTime", LocalDateUtils.dateTimeFormat(project.getProjectEnd()));
    }};
  }

  private <T> DefaultUploadResult<T> buildTeamUploadResult(MultipartFile file, Class<T> clazz,
      Consumer<List<T>> consumer) {
    if (!file.isEmpty()) {
      final String extension = FileTypeUtils.getExtension(file);
      if (!StringUtils.equalsAnyIgnoreCase(extension, MimeTypeUtils.EXCEL_EXTENSION)) {
        throw new ServiceException(
            "文件格式不正确，请上传" + Arrays.toString(MimeTypeUtils.IMAGE_EXTENSION) + "格式");
      }
      //读取文件解析成团队列表
      ExcelUtil<T> excel = new ExcelUtil<>(clazz);
      List<T> dataList;
      try {
        dataList = excel.importExcel(file.getInputStream());
      } catch (IOException e) {
        log.error("文件解析异常", e);
        throw new ServiceException("文件解析异常,请下载模板,填充数据上传(不要修改文件格式)");
      }
      if (CollUtil.isEmpty(dataList)) {
        throw new ServiceException("文件内容为空");
      }
      consumer.accept(dataList);
      final R<SysFile> fileResult = remoteFileService.upload(file);
      if (StringUtils.isNull(fileResult) || StringUtils.isNull(fileResult.getData())) {
        throw new ServiceException("文件服务异常，请联系管理员");
      }
      final String url = fileResult.getData().getUrl();
      final String fileName = file.getOriginalFilename();
      final FileContentEntity entity = fileBusiness.saveFileContent(fileName, url,
          JSONUtil.toJsonStr(dataList));
      DefaultUploadResult<T> uploadResult = new DefaultUploadResult<>();
      uploadResult.setFileUrl(url);
      uploadResult.setFileKey(entity.getFileKey());
      uploadResult.setFileName(fileName);
      uploadResult.setList(dataList);
      return uploadResult;
    }
    throw new ServiceException("文件上传异常，请联系管理员");
  }

  private void dealTeamList(List<Team> teamList) {
    //暂时不校验,缺少时间
    //log.info("团队列表:" + JSONUtil.toJsonStr(teamList));
    //岗位名称校验
    final Map<String, String> postNameMap = dictBusiness.checkDictDescAndGetMap(
        DictTypeEnum.POST, teamList.stream().map(Team::getPostName)
            .collect(Collectors.toList()));
    //岗位等级校验
    final Map<String, String> postLevelMap = dictBusiness.checkDictDescAndGetMap(
        DictTypeEnum.POST_LEVEL, teamList.stream().map(Team::getPostLevel)
            .collect(Collectors.toList()));
    //数据校验
    teamList.forEach(team -> {
      //总金额核对
      if (team.getSalaryTotal().compareTo(team.getSalaryByDay()
          .multiply(BigDecimal.valueOf(team.getPersonDay()))) != 0) {
        throw new ServiceException("团队列表金额错误");
      }
      team.setPostCode(postNameMap.get(team.getPostName()))
          .setPostLevelCode(postLevelMap.get(team.getPostLevel()));
    });
    teamList.stream().collect(Collectors.groupingBy(Team::buildCompareKey))
        .forEach((k, v) -> {
          if (v.size() > 1) {
            throw new ServiceException("岗位,岗位等级重复记录,请合并后上传");
          }
        });
  }

  private void dealReserveFundDetail(List<ReserveFundDetail> reserveFundDetails) {
    //暂时不校验,缺少时间
    //log.info("备用金明细:" + JSONUtil.toJsonStr(reserveFundDetails));
  }

  private void dealDemandList(List<Demand> demandList) {
    //暂时不校验,缺少时间
    //log.info("需求列表:" + JSONUtil.toJsonStr(demandList));
  }

  private void checkProjectObj(ProjectObj projectObj) {
    //备用金为是,备用金额和备用金明细必须有值
    if (YesNoEnum.YES.eqCode(projectObj.getHasReserveFund())) {
      // 备用金额
      CommonUtils.assertsTrueWithMessage(Objects.nonNull(projectObj.getReserveFund())
          && projectObj.getReserveFund().compareTo(BigDecimal.ZERO) > 0, "备用金 金额必须大于0"
      );
      // 备用金明细不能为空,以下两个字段值是对值
      CommonUtils.assertsFieldHasText(projectObj.getReserveFundDetailFile(), "备用金明细");
      CommonUtils.assertsFieldHasText(projectObj.getReserveFundDetailFileKey(), "备用金明细");
    }
    //验证fileKey
    final List<String> fileKeys = new ArrayList<>();
    fileKeys.add(projectObj.getTeamListFileKey());
    fileKeys.add(projectObj.getDemandListFileKey());
    if (StringUtils.isNotBlank(projectObj.getReserveFundDetailFileKey())) {
      fileKeys.add(projectObj.getReserveFundDetailFileKey());
    }
    final Map<String, FileContentEntity> fileMap = Optional.ofNullable(
        fileBusiness.listByFileKeys(fileKeys)).orElseGet(ArrayList::new).stream().collect(
        Collectors.toMap(FileContentEntity::getFileKey, v -> v, (v1, v2) -> v1));
    //校验备用金明细汇总金额是否与备用金金额一致
    if (StringUtils.isNotBlank(projectObj.getReserveFundDetailFileKey())
        && !fileMap.containsKey(projectObj.getReserveFundDetailFileKey())) {
      throw new ServiceException("请重新上传备用金明细文件");
    }
    final List<ReserveFundDetail> reserveFundDetails = fileBusiness.dataListByFileKey(
        projectObj.getReserveFundDetailFileKey(), ReserveFundDetail.class);
    if (CollUtil.isNotEmpty(reserveFundDetails)) {
      final BigDecimal totalAmount = reserveFundDetails.stream().map(ReserveFundDetail::getAmount)
          .reduce(BigDecimal::add).orElse(BigDecimal.ZERO);
      if (totalAmount.compareTo(projectObj.getReserveFund()) != 0) {
        throw new ServiceException("备用金明细汇总金额与备用金金额不一致,请重新上传备用金明细文件");
      }
    }
    //校验团队列表
    if (!fileMap.containsKey(projectObj.getTeamListFileKey())) {
      throw new ServiceException("请重新上传团队列表文件");
    }
    //验证需求列表
    if (!fileMap.containsKey(projectObj.getDemandListFileKey())) {
      throw new ServiceException("请重新上传需求列表文件");
    }

  }

  private void fillBaseInfo(ProjectEntity projectEntity, ProjectExtEntity projectExtEntity) {
    //补充区域信息
    final String executionPlace = projectEntity.getExecutionPlace();
    if (StringUtils.isNotBlank(executionPlace)) {
      final String[] split = executionPlace.split(",");
      List<Integer> ids = new ArrayList<>(split.length);
      for (String s : split) {
        if (StringUtils.isNotBlank(s)) {
          ids.add(Integer.parseInt(s));
        }
      }
      final Map<Integer, RegionEntity> regioMap = Optional.ofNullable(regionBusiness.listByIds(ids))
          .orElseGet(ArrayList::new).stream()
          .collect(Collectors.toMap(RegionEntity::getId, v -> v, (v1, v2) -> v1));
      List<String> nameList = new ArrayList<>();
      for (String s : split) {
        if (StringUtils.isNotBlank(s)) {
          final RegionEntity region = CommonUtils.requireNotNull(
              regioMap.get(Integer.parseInt(s)), "市区编码不合法");
          nameList.add(region.getName());
        }
      }
      projectEntity.setExecutionPlaceDesc(String.join(",", nameList));
    }

    projectEntity
        .setComId(Optional.ofNullable(projectEntity.getComId())
            .orElseGet(() -> UserUtil.getLoginUser().getCompanyId()))
        .setCreateBy(Optional.ofNullable(projectEntity.getCreateBy())
            .orElseGet(UserUtil::getUserId))
        .setCreateTime(Optional.ofNullable(projectEntity.getCreateTime())
            .orElseGet(LocalDateTime::now))
        .setUpdateBy(UserUtil.getUserId())
        .setUpdateTime(LocalDateTime.now());
    projectExtEntity
        .setCreateBy(Optional.ofNullable(projectExtEntity.getCreateBy())
            .orElseGet(UserUtil::getUserId))
        .setCreateTime(Optional.ofNullable(projectExtEntity.getCreateTime())
            .orElseGet(LocalDateTime::now))
        .setUpdateBy(UserUtil.getUserId())
        .setUpdateTime(LocalDateTime.now());
  }

  private void updateEntity(ProjectEntity projectEntity, ProjectExtEntity projectExtEntity,
      ProjectObj projectObj) {
    if (ProjectStatusEnum.CREATE.eqCode(projectEntity.getStatus())) {
      //一旦发布以下值不能修改
      projectEntity.setProjectStart(projectObj.getProjectStart())
          .setProjectLeader(projectObj.getProjectLeader());
    }
    projectEntity.setProjectName(projectObj.getProjectName())
        .setServiceBrand(projectObj.getServiceBrand())
        .setServiceModel(projectObj.getServiceModel())
        .setProjectType(projectObj.getProjectType())
        .setExecutionPlace(projectObj.getExecutionPlace())
        .setHasReserveFund(projectObj.getHasReserveFund())
        .setReserveFund(projectObj.getReserveFund())
        .setProjectEnd(projectObj.getProjectEnd())
        .setProjectOverview(projectObj.getProjectOverview())
        .setKeyItems(projectObj.getKeyItems())
        .setProjectBudget(projectObj.getProjectBudget())
        .setLockedAmount(
            platFormConfig.calculateAmountContainCommission(projectObj.getProjectBudget()))
        .setUpdateBy(UserUtil.getUserId())
        .setUpdateTime(LocalDateTime.now());
    projectExtEntity.setReserveFundDetailFile(projectObj.getReserveFundDetailFile())
        .setReserveFundDetailFileKey(projectObj.getReserveFundDetailFileKey())
        .setTeamListFile(projectObj.getTeamListFile())
        .setTeamListFileKey(projectObj.getTeamListFileKey())
        .setDemandListFile(projectObj.getDemandListFile())
        .setDemandListFileKey(projectObj.getDemandListFileKey())
        .setUpdateBy(UserUtil.getUserId())
        .setUpdateTime(LocalDateTime.now())
    ;
  }


  private ProjectLogModel buildAndCheckProjectChangeLog(ProjectObj before, ProjectObj after) {
    final ProjectLogModel projectLogModel = new ProjectLogModel()
        .setProjectId(before.getId())
        .setProjectLogList(new ArrayList<ProjectLogDetail>() {{
          if (hasChanged(before.getProjectName(), after.getProjectName())) {
            add(new ProjectLogDetail()
                .setChangeField("项目名称")
                .setBefore(Optional.ofNullable(before.getProjectName()).orElse(""))
                .setAfter(Optional.ofNullable(after.getProjectName()).orElse("")));
          }
          if (hasChanged(before.getServiceBrand(), after.getServiceBrand())) {
            add(new ProjectLogDetail().setChangeField("服务品牌")
                .setBefore(Optional.ofNullable(before.getServiceBrand()).orElse(""))
                .setAfter(Optional.ofNullable(after.getServiceBrand()).orElse("")));
          }
          if (hasChanged(before.getServiceModel(), after.getServiceModel())) {
            add(new ProjectLogDetail().setChangeField("服务车型")
                .setBefore(Optional.ofNullable(before.getServiceModel()).orElse(""))
                .setAfter(Optional.ofNullable(after.getServiceModel()).orElse("")));
          }
          if (hasChanged(before.getProjectType(), after.getProjectType())) {
            add(new ProjectLogDetail().setChangeField("项目类型")
                .setBefore(Optional.ofNullable(before.getProjectType()).orElse(""))
                .setAfter(Optional.ofNullable(after.getProjectType()).orElse("")));
          }
          if (hasChanged(before.getExecutionPlace(), after.getExecutionPlace())) {
            add(new ProjectLogDetail().setChangeField("执行地点")
                .setBefore(Optional.ofNullable(before.getExecutionPlace()).orElse(""))
                .setAfter(Optional.ofNullable(after.getExecutionPlace()).orElse("")));
          }
          if (hasChanged(before.getHasReserveFund(), after.getHasReserveFund())) {
            add(new ProjectLogDetail().setChangeField("是否备用金")
                .setBefore(
                    YesNoEnum.getByCode(Optional.ofNullable(before.getHasReserveFund()).orElse(0))
                        .getName())
                .setAfter(
                    YesNoEnum.getByCode(Optional.ofNullable(after.getHasReserveFund()).orElse(0))
                        .getName()));
          }
          if (hasChanged(before.getReserveFund(), after.getReserveFund())) {
            add(new ProjectLogDetail().setChangeField("备用金金额")
                .setBefore(CommonUtils.decimalFormatNullToBlank(before.getReserveFund()))
                .setAfter(CommonUtils.decimalFormatNullToBlank(after.getReserveFund())));
          }
          if (hasChanged(before.getReserveFundDetailFileKey(),
              after.getReserveFundDetailFileKey())) {
            add(new ProjectLogDetail().setChangeField("备用金预算明细文件")
                .setIsFileUrl(YesNoEnum.YES.getCode())
                .setBefore(Optional.ofNullable(before.getReserveFundDetailFile()).orElse(""))
                .setAfter(Optional.ofNullable(after.getReserveFundDetailFile()).orElse("")));
          }
          if (hasChanged(before.getProjectStart(), after.getProjectStart())) {
            throw new ServiceException("项目周期开始时间不能修改");
          }
          if (hasChanged(before.getProjectEnd(), after.getProjectEnd())) {
            add(new ProjectLogDetail().setChangeField("项目周期结束时间")
                .setBefore(LocalDateUtils.dateTimeFormatNullForBlank(before.getProjectEnd()))
                .setAfter(LocalDateUtils.dateTimeFormatNullForBlank(after.getProjectEnd())));
          }
          if (hasChanged(before.getProjectOverview(), after.getProjectOverview())) {
            add(new ProjectLogDetail().setChangeField("项目概况")
                .setBefore(Optional.ofNullable(before.getProjectOverview()).orElse(""))
                .setAfter(Optional.ofNullable(after.getProjectOverview()).orElse("")));
          }
          if (hasChanged(before.getKeyItems(), after.getKeyItems())) {
            add(new ProjectLogDetail().setChangeField("重点事项")
                .setBefore(Optional.ofNullable(before.getKeyItems()).orElse(""))
                .setAfter(Optional.ofNullable(after.getKeyItems()).orElse("")));
          }
          if (hasChanged(before.getTeamListFileKey(), after.getTeamListFileKey())) {
            add(new ProjectLogDetail().setChangeField("团队列表文件")
                .setIsFileUrl(YesNoEnum.YES.getCode())
                .setBefore(Optional.ofNullable(before.getTeamListFile()).orElse(""))
                .setAfter(Optional.ofNullable(after.getTeamListFile()).orElse("")));
          }
          if (hasChanged(before.getDemandListFileKey(), after.getDemandListFileKey())) {
            add(new ProjectLogDetail().setChangeField("需求列表文件")
                .setIsFileUrl(YesNoEnum.YES.getCode())
                .setBefore(Optional.ofNullable(before.getDemandListFile()).orElse(""))
                .setAfter(Optional.ofNullable(after.getDemandListFile()).orElse("")));
          }
          if (hasChanged(before.getProjectBudget(), after.getProjectBudget())) {
            add(new ProjectLogDetail().setChangeField("项目预算")
                .setBefore(CommonUtils.decimalFormatNullToBlank(before.getProjectBudget()))
                .setAfter(CommonUtils.decimalFormatNullToBlank(after.getProjectBudget())));
          }
          if (hasChanged(before.getProjectLeader(), after.getProjectLeader())) {
            throw new ServiceException("项目负责人不能修改");
          }
        }});
    projectLogModel.getProjectLogList().forEach(logDetail -> {
      logDetail.setChangeType(ProjectLogTypeEnum.PROJECT_EDIT.getName());
    });
    if (CollUtil.isEmpty(projectLogModel.getProjectLogList())) {
      throw new ServiceException("无修改项");
    }
    return projectLogModel;
  }

  private boolean hasChanged(BigDecimal before, BigDecimal after) {
    if (before == null && after == null) {
      return false;
    }
    if (Objects.nonNull(before) && Objects.nonNull(after)) {
      return before.compareTo(after) != 0;
    }
    return true;
  }

  private boolean hasChanged(Long before, Long after) {
    if (before == null && after == null) {
      return false;
    }
    if (Objects.isNull(before) || Objects.isNull(after)) {
      return true;
    }
    return before.compareTo(after) != 0;
  }

  private boolean hasChanged(Integer before, Integer after) {
    if (before == null && after == null) {
      return false;
    }
    if (Objects.isNull(before) || Objects.isNull(after)) {
      return true;
    }
    return before.compareTo(after) != 0;
  }

  private boolean hasChanged(LocalDateTime before, LocalDateTime after) {
    return !LocalDateUtils.dateTimeFormatNullForBlank(before)
        .equals(LocalDateUtils.dateTimeFormatNullForBlank(after));
  }

  private boolean hasChanged(String before, String after) {
    if (before == null && after == null) {
      return false;
    }
    return !Optional.ofNullable(before).orElse("").equals(after);
  }

  private ProjectLogModel buildProjectLogSimple(String projectId, ProjectLogTypeEnum logTypeEnum,
      String before, String after) {
    return new ProjectLogModel()
        .setProjectId(projectId)
        .setProjectLogList(new ArrayList<ProjectLogDetail>() {{
          add(new ProjectLogDetail().setChangeField(logTypeEnum.getName())
              .setBefore(Optional.ofNullable(before).orElse(""))
              .setAfter(Optional.ofNullable(after).orElse("")));
        }});
  }

  private CommonPageInfo<ProjectSimple> convert(CommonPageInfo<ProjectEntity> pageInfo) {
    final CommonPageInfo<ProjectSimple> convert = pageInfo.convert(
        ProjectConverter.INSTANCE::toProjectSimple);
    if (CollUtil.isNotEmpty(convert.getList())) {
      fillUserInfo(convert.getList());
      fillLaborCount(convert.getList());
//      final List<Long> userList = convert.getList().stream().map(ProjectSimple::getProjectLeader)
//          .collect(Collectors.toList());
//      final Map<Long, UserEntity> userMap = Optional.ofNullable(userBusiness.getListByIds(userList))
//          .orElseGet(ArrayList::new).stream()
//          .collect(Collectors.toMap(UserEntity::getUserId, v -> v, (v1, v2) -> v1));
//      convert.getList().forEach(v -> {
//        final UserEntity userEntity = userMap.get(v.getProjectLeader());
//        if (Objects.nonNull(userEntity)) {
//          v.setProjectLeaderName(userEntity.getName())
//              .setProjectLeaderPhone(userEntity.getPhone());
//        }
//      });
    }
    return convert;
  }

  private void fillLaborCount(List<ProjectSimple> simpleList) {
    final List<String> projectIdList = simpleList.stream().map(ProjectSimple::getId)
        .collect(Collectors.toList());
    Map<String,Long> laborCountMap = projectLaborService.getProjectLaborCountMap(projectIdList);
    simpleList.forEach(v -> {
      v.setLaborCount(laborCountMap.getOrDefault(v.getId(), 0L));
    });
  }

  private void calcPostInfo(ProjectEntity projectEntity, String teamListFileKey) {
    //未发布处理
    if (Objects.isNull(projectEntity.getStatus()) || ProjectStatusEnum.CREATE.eqCode(
        projectEntity.getStatus())) {
      final List<Team> teams = fileBusiness.dataListByFileKey(teamListFileKey, Team.class);
      //
      List<PostInfo> postInfos = new ArrayList<>();
      teams.forEach(team -> {
        //岗位信息
        postInfos.add(buildNewPostInfoFromTeam(team));
      });
      //补充岗位信息
      projectEntity.setPostsInfoList(postInfos);
      return;
    }
    //已发布后的修改
    if (projectEntity.getStatus() > ProjectStatusEnum.CREATE.getCode()) {
      //取旧值
      final ProjectExtEntity projectExtEntity = projectExtService.selectByProjectId(
          projectEntity.getId());
      //判断团队列表是不是发生变化
      if (hasChanged(projectExtEntity.getTeamListFileKey(), teamListFileKey)) {
        final List<PostInfo> postInfoList = JSONUtil.toList(projectEntity.getPostsInfo(),
            PostInfo.class);
        //新岗位列表
        final List<Team> teams = fileBusiness.dataListByFileKey(teamListFileKey, Team.class);
        if (postInfoList.size() > teams.size()) {
          throw new ServiceException("发生岗位缩编,禁止操作,或者联系管理员处理");
        }
        final Map<String, Team> teamMap = teams.stream()
            .collect(Collectors.toMap(Team::buildCompareKey, Function.identity(),
                (v1, v2) -> v1));
        //旧的岗位和等级在新的岗位列表中必须存在,并且相关信息只能扩编,不能缩编
        postInfoList.forEach(postInfo -> {
          final String key = postInfo.buildCompareKey();
          if (!teamMap.containsKey(key)) {
            throw new ServiceException("发生岗位减少,禁止操作,或者联系管理员处理");
          }
          final Team team = teamMap.get(key);
          //必要值对比
          if (postInfo.getNumber() > team.getNumber()) {
            throw new ServiceException("发生岗位人数减少,禁止操作,或者联系管理员处理");
          }
          if (postInfo.getPersonDay() > team.getPersonDay()) {
            throw new ServiceException("发生岗位人天减少,禁止操作,或者联系管理员处理");
          }
          if (postInfo.getSalaryByDay().compareTo(team.getSalaryByDay()) > 0) {
            throw new ServiceException("发生岗位薪资减少,禁止操作,或者联系管理员处理");
          }
          postInfo.setNumber(team.getNumber())
              .setPersonDay(team.getPersonDay())
              .setSalaryByDay(team.getSalaryByDay())
              .setSalaryTotal(team.getSalaryTotal());
        });
        final Map<String, PostInfo> existPostMap = postInfoList.stream()
            .collect(
                Collectors.toMap(PostInfo::buildCompareKey, Function.identity(), (v1, v2) -> v1));
        //新增岗位
        teams.stream().filter(team -> !existPostMap.containsKey(team.buildCompareKey()))
            .forEach(team -> {
              postInfoList.add(buildNewPostInfoFromTeam(team));
            });
        // 处理雇佣情况
        postInfoList.forEach(PostInfo::updateHireStatus);
        projectEntity.setPostsInfoList(postInfoList);
        return;
      }
    }
  }

  private PostInfo buildNewPostInfoFromTeam(Team team) {
    return new PostInfo()
        .setIsHiring(YesNoEnum.YES.getCode())
        .setPostCode(team.getPostCode())
        .setPostName(team.getPostName())
        .setLevelCode(team.getPostLevelCode())
        .setLevel(team.getPostLevel())
        .setNumber(team.getNumber())
        .setPersonDay(team.getPersonDay())
        .setSalaryByDay(team.getSalaryByDay())
        .setSalaryTotal(team.getSalaryTotal())
        .setHiredNumber(0)
        .setHiredPersonDay(0)
        .setHiredSalaryTotal(BigDecimal.ZERO);
  }


  public void finishWork(String projectId) {
    projectLaborBusiness.finishWork(projectId);
  }

  public UploadResult uploadReport(MultipartFile file) {
    if (!file.isEmpty()) {
      final String extension = FileTypeUtils.getExtension(file);
      if (!extension.equals("pdf")) {
        throw new ServiceException("文件格式不正确，请上传pdf格式");
      }
      final R<SysFile> fileResult = remoteFileService.upload(file);
      if (StringUtils.isNull(fileResult) || StringUtils.isNull(fileResult.getData())) {
        throw new ServiceException("文件服务异常，请联系管理员");
      }
      final String url = fileResult.getData().getUrl();
      final String fileName = file.getOriginalFilename();
      final FileContentEntity entity = fileBusiness.saveFileContent(fileName, url,
          JSONUtil.toJsonStr(new Object()));
      UploadResult uploadResult = new UploadResult();
      uploadResult.setFileUrl(url);
      uploadResult.setFileKey(entity.getFileKey());
      uploadResult.setFileName(fileName);
      return uploadResult;
    }
    return null;
  }

  public List<ProjectSimple> simpleListByIds(List<String> projectIds) {
    final List<ProjectEntity> projectEntities = projectService.listByIds(projectIds);
    if (CollUtil.isEmpty(projectEntities)) {
      return new ArrayList<>();
    }
    final List<ProjectSimple> simpleList = projectEntities.stream()
        .map(ProjectConverter.INSTANCE::toProjectSimple).collect(Collectors.toList());
    fillUserInfo(simpleList);
    return simpleList;
  }

  private void fillUserInfo(List<ProjectSimple> simpleList) {
    final List<Long> userList = simpleList.stream().map(ProjectSimple::getProjectLeader)
        .collect(Collectors.toList());
    final Map<Long, UserEntity> userMap = userService.userMapByIds(userList);
    simpleList.forEach(v -> {
      final UserEntity userEntity = userMap.get(v.getProjectLeader());
      if (Objects.nonNull(userEntity)) {
        v.setProjectLeaderName(userEntity.getName())
            .setProjectLeaderPhone(userEntity.getPhone());
      }
    });
  }

  /**
   * 延期提醒
   */
  public void notifyDelay() {
    final List<ProjectEntity> projectEntityList = projectService.delayNotifyList();
    if (CollUtil.isEmpty(projectEntityList)) {
      return;
    }
    projectEntityList.forEach(project -> {
      //每一个项目ID锁定6分钟,避免重复发送
      final String key = StringUtils.format("project:notifyDelay:key:{}", project.getId());
      if (redisService.setIfAbsent(key, "1", 6, TimeUnit.MINUTES)) {
        try {
          //发给项目创建人
          messageBusiness.addMessage(MessageTemplateEnum.A16,
              buildProperties(project), project.getId(),
              project.getCreateBy(), companyService.getNameById(project.getComId()),
              project.getProjectLeader());
          //发给项目leader
          messageBusiness.addMessage(MessageTemplateEnum.A17,
              buildProperties(project), project.getId(),
              project.getProjectLeader(),
              companyService.getNameById(project.getComId()),
              project.getCreateBy());
        } catch (Exception e) {
          redisService.deleteObject(key);
        }
      }
    });
  }

//  /**
//   * 项目方 已合作项目数
//   */
//  public Long getDemanderCooperationCount() {
//    return projectService.countForCooperation(UserUtil.getUserId());
//  }

  /**
   * 已合作项目[项目方]
   */
  public CommonPageInfo<ProjectSimple> demanderListForCooperation(
      ProjectQueryForDemander projectQuery) {
    final CommonPageInfo<ProjectEntity> pageInfo = PageUtils.startPage(projectQuery);
    pageInfo.initData(
        projectService.demanderListForCooperation(projectQuery, UserUtil.getUserId()));
    return convert(pageInfo);
  }

  /**
   * 待验收项目[项目方]
   */
  public CommonPageInfo<ProjectSimple> demanderListForVery(ProjectQueryForDemander projectQuery) {
    final CommonPageInfo<ProjectEntity> pageInfo = PageUtils.startPage(projectQuery);
    pageInfo.initData(projectService.demanderListForVery(projectQuery, UserUtil.getUserId()));
    return convert(pageInfo);
  }

  /**
   * 执行中的项目[项目方]
   */
  public CommonPageInfo<ProjectSimple> demanderListForExecution(
      ProjectQueryForDemander projectQuery) {
    final CommonPageInfo<ProjectEntity> pageInfo = PageUtils.startPage(projectQuery);
    pageInfo.initData(projectService.demanderListForExecution(projectQuery, UserUtil.getUserId()));
    return convert(pageInfo);
  }

  public CommonPageInfo<ProjectSimple> demanderListForSudden(ProjectQueryForDemander projectQuery) {
    final CommonPageInfo<ProjectEntity> pageInfo = PageUtils.startPage(projectQuery);
    pageInfo.initData(projectService.demanderListForSudden(projectQuery, UserUtil.getUserId()));
    return convert(pageInfo);
  }

  public CommonPageInfo<ProjectSimple> laborListForFinish(ProjectQueryForDemander projectQuery) {
    final CommonPageInfo<ProjectEntity> pageInfo = PageUtils.startPage(projectQuery);
    pageInfo.initData(projectService.laborListForFinish(projectQuery, UserUtil.getUserId()));
    return convert(pageInfo);
  }


  public CommonPageInfo<ProjectSimple> laborListForApply(ProjectQueryForDemander projectQuery) {
    final CommonPageInfo<ProjectEntity> pageInfo = PageUtils.startPage(projectQuery);
    pageInfo.initData(projectService.laborListForApply(projectQuery, UserUtil.getUserId()));
    return convert(pageInfo);
  }

  public CommonPageInfo<ProjectSimple> laborListForExecution(ProjectQueryForDemander projectQuery) {
    final CommonPageInfo<ProjectEntity> pageInfo = PageUtils.startPage(projectQuery);
    pageInfo.initData(projectService.laborListForExecution(projectQuery, UserUtil.getUserId()));
    return convert(pageInfo);
  }
}
